package com.pengyeah.bigbitmapcanary

import android.app.Activity
import android.app.Application
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.pengyeah.bigbitmapcanary.constant.Constant
import com.pengyeah.bigbitmapcanary.utils.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.util.*
import kotlin.collections.ArrayList

object BitmapCanary {
    lateinit var context: Application

    var isOpenLog: Boolean = true
    var isWriteLog: Boolean = true
    var isShowToast: Boolean = true

    var rate: Float = 1.2F

    fun install(ctx: Application) {
        checkMainThread()
        context = ctx
        registerActivityLifecycleCallback(context)
        LogUtils.isOpenLog = isOpenLog
    }

    private fun registerActivityLifecycleCallback(application: Application) {
        application.registerActivityLifecycleCallbacks(object :
            Application.ActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                Log.i(Constant.TAG, "onActivityCreated:" + activity::class.java.name)
            }

            override fun onActivityStarted(activity: Activity) {
                Log.i(Constant.TAG, "onActivityStarted:" + activity::class.java.name)
            }

            override fun onActivityResumed(activity: Activity) {
                Log.i(Constant.TAG, "onActivityResumed:" + activity::class.java.name)
            }

            override fun onActivityPaused(activity: Activity) {
                Log.i(Constant.TAG, "onActivityPaused:" + activity::class.java.name)
            }

            override fun onActivityStopped(activity: Activity) {
                Log.i(Constant.TAG, "onActivityStopped:" + activity::class.java.name)
                val fragments: List<Fragment>? = getAllFragmentsFromActivity(activity)
                fragments?.let {
                    for (fragment in it) {
                        Log.i(Constant.TAG, "fragment:$fragment")
                        val childViews: List<View> = getAllChildViews(fragment.view!!)
                        checkBitmapIsTooBig(childViews, fragment::class.java.name)
                        Log.i(Constant.TAG, "childViews==>$childViews")
                    }
                    return
                }
                val childViews: List<View> = getAllChildViews(activity.window.decorView)
                Log.i(Constant.TAG, "$childViews")
                checkBitmapIsTooBig(childViews)
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
                Log.i(Constant.TAG, "onActivitySaveInstanceState:" + activity::class.java.name)
            }

            override fun onActivityDestroyed(activity: Activity) {
                Log.i(Constant.TAG, "onActivityDestroyed:" + activity::class.java.name)
            }

        })
    }

    private fun getAllFragmentsFromActivity(activity: Activity): List<Fragment>? {
        if (activity is FragmentActivity) {
            return activity.supportFragmentManager.fragments
        }
        return null
    }

    private fun getAllChildViews(view: View): List<View> {
        val allChildren = ArrayList<View>()
        if (view is ViewGroup) {
            for (i in 0..view.childCount) {
                val viewChild: View = view.getChildAt(i) ?: return allChildren
                allChildren.add(viewChild)
                allChildren.addAll(getAllChildViews(viewChild))
            }
        }
        return allChildren
    }

    /**
     * 检查图片是否过大
     */
    private fun checkBitmapIsTooBig(views: List<View>, containerName: String? = null) {
        for (view in views) {
            if (isTooBig(view, containerName)) {
                if (!isShowToast) {
                    return
                }
                //show alert toast
                showAlertToast(
                    context,
                    if (TextUtils.isEmpty(containerName)) findActivityNameByView(view) else containerName,
                    view::class.java.simpleName,
                    findViewIDNameByView(context, view)
                )
            }
        }
    }

    /**
     * 判断view图片是否过大，重点检查ImageView
     */
    private fun isTooBig(view: View, containerName: String? = null): Boolean {
        val viewName = findViewIDNameByView(context, view)
        val activityName =
            if (TextUtils.isEmpty(containerName)) findActivityNameByView(view) else containerName
        if (view is ImageView) {
            if (view.drawable !is BitmapDrawable) {
                return false
            }
            val bmDrawable: BitmapDrawable? = view.drawable as BitmapDrawable?
            val bm: Bitmap? = bmDrawable?.bitmap
            bm?.let {
                if (it.width > rate * view.width || it.height > rate * view.height) {
                    logWarn(
                        activityName,
                        viewName,
                        view::class.java.simpleName,
                        it.width,
                        it.height,
                        view.width,
                        view.height
                    )
                    return true
                }
            }
        }
        //取背景图片
        val drawable = view.background
        if (drawable is BitmapDrawable) {
            val bm: Bitmap? = drawable.bitmap
            bm?.let {
                if (it.width > rate * view.width || it.height > rate * view.height) {
                    logWarn(
                        activityName,
                        viewName,
                        view::class.java.simpleName,
                        it.width,
                        it.height,
                        view.width,
                        view.height
                    )
                    return true
                }
            }
        }
        return false
    }

    private fun logWarn(
        activityName: String?,
        viewName: String?,
        viewClassName: String?,
        realWidth: Int,
        realHeight: Int,
        desiredWidth: Int,
        desiredHeight: Int
    ) {
        val warnInfo = StringBuilder("Bitmap size too large!!! ")
            .append("\n Activity Name:($activityName)")
            .append("\n View Id Name:($viewName)")
            .append("\n View Class Name:($viewClassName)")
            .append("\n real width: ($realWidth)")
            .append("\n real height: ($realHeight)")
            .append("\n desired width: ($desiredWidth)")
            .append("\n desired height: ($desiredHeight)")
            .toString()
        Log.i(Constant.TAG, warnInfo)


        write2Log(context, warnInfo)
    }

    /**
     * 弹出警告吐司
     */
    private fun showAlertToast(
        context: Context,
        containerName: String?,
        viewClassName: String? = "",
        viewIdName: String? = ""
    ) {
        checkMainThread()
        showToast(
            context,
            "Bitmap is too big!!!\n" +
                    "activityName:$containerName;\n" +
                    "viewClassName:$viewClassName\n" +
                    "viewIdName:$viewIdName"
        )
    }

    /**
     * 写文件记录大图片
     */
    private fun write2Log(context: Context, content: String) {
        if (!isWriteLog) {
            return
        }
        //写文件
        GlobalScope.launch(Dispatchers.IO) {
            val filePath =
                context.applicationContext.filesDir.path + File.separator + Constant.TAG + "_" + formatDate(
                    Date()
                ) + ".log"
            LogUtils.i(Constant.TAG, "filePath==>$filePath")
            writeLog(filePath, content)
        }
    }
}
